/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFOnlineCache
  \brief to store online events for all daqs and present matched event combination
  to online source for aligned-daq data analysis
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2024-06-25
  \date 2024-06-29 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date        <th>Author      <th>Description                    </tr>
  <tr>  <td>2024-06-25   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include "ETFOnlineCache.h"
#include "ETFDaqData.h"
#include "ETFQueue.h"
#include "ETFMsg.h"

ETFOnlineCache::ETFOnlineCache() : fNLoaded(0), fIndex(0), fCntEv(0), fNDaq(0){}

ETFOnlineCache::~ETFOnlineCache(){
  for(auto &d : fDaqs) delete d;
} // end dtor

void ETFOnlineCache::AddDaq(ETFUnpacker *u, ETFDaqData *q){
  auto d = new online_daq_t({.upk = u, .daq = q});
  memset(d->cache, 0, sizeof(d->cache));
  memset(d->idx, 0, sizeof(d->idx));
  fDaqs.push_back(d);
  fMatchedId.push_back(-1);
  fNDaq++;
} // end member function AddDaq

// load a number of events, then do matching within them
// after all matches are exhausted, clear the cache and reload
bool ETFOnlineCache::GetOneEvent(){
  if(!fNLoaded){ // load the caches if empty
    for(auto &d : fDaqs) if(d->daq->queue()->NLoaded() < CACHE_DEPTH) return false;
    for(auto &d : fDaqs) for(int i = 0; i < CACHE_DEPTH; i++) d->daq->Get(d->cache[i], d->idx[i]);
    fNLoaded = CACHE_DEPTH;
  } // end else

  // loop over all UNUSED evs in the 1st daq //
  for(int i = CACHE_DEPTH - fNLoaded; i < CACHE_DEPTH; i++){
    fNLoaded--; fCntEv++;
    fIndex = fDaqs[0]->idx[i];
    int iim = -1;
    bool matched = true;
    fMatchedId[0] = i;
    for(int j = 1; j < fNDaq; j++){
      if((iim = fDaqs[j]->find(fIndex)) != -1) fMatchedId[j] = iim;
      // plain mode - use the following line in the stead of the above line
      // if a match can not be found all the time
      // fMatchedId[j] = i;
      else{ matched = false; break; }
    } // end for over other daqs
    if(matched){ // mark the matched index as 'used'
      for(int j = 1; j < fNDaq; j++) fDaqs[j]->idx[fMatchedId[j]] = UINT_MAX;
      return true;
    } // end if
  } // end for over events

  // if no match is spotted in the whole CACHE_DEPTH range, issue an warning
  if(fNDaq > 1){
    bool nomatch = true;
    for(const auto &id : fDaqs[1]->idx) if(id != UINT_MAX) nomatch = false;
    if(nomatch)
      ETFMsg::Warn("ETFOnlineCache", "GetOneEvent: Failed to find a match in the"
        "whole %d consecutive cached events", CACHE_DEPTH);
  } // end if
  return false;
} // end member function GetOneEvent

void ETFOnlineCache::Clear(){
  for(auto &d : fDaqs) d->daq->Reset();
  fCntEv += fNLoaded;
  fNLoaded = 0;
} // end member function Clear
